package com.share.device.emqx;

import com.share.device.emqx.callback.OnMessageCallback;
import com.share.device.emqx.constants.EmqxConstants;
import com.share.device.emqx.properties.EmqxProperties;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 封装mqtt对 emqx服务器的相关操作
 * 连接 发送 订阅等
 */
@Slf4j
@Component
public class EmqxClientUtil {

    @Autowired
    private EmqxProperties emqxProperties;
    @Autowired
    private OnMessageCallback onMessageCallback;

    private MqttClient client;


    //初始化： mqtt服务创建对emqx的连接 对象创建后自动调用
    @PostConstruct
    private void init(){
        //mqtt client持久化存储对象 存储在内存中 重连时保证数据能够恢复
        MqttClientPersistence mqttClientPersistence = new MemoryPersistence();


        try {

            //实例化客户端
            client = new MqttClient(emqxProperties.getServerURI(),emqxProperties.getClientId(),mqttClientPersistence);

            //设置回调函数对象
            client.setCallback(onMessageCallback);

            //连接到mqtt
            connect();

        } catch (MqttException e) {
            log.info("MqttClient创建失败");
            throw new RuntimeException(e);
        }

    }

    //client连接到mqtt 指定topic，连接成功返回true 失败返回false
    public Boolean connect() {

        //通过连接对象配置类连接
        try {
            client.connect(mqttConnectOptions());
            log.info("连接成功");

            //与topic进行绑定
            //所有的topic
            String[] topics = {EmqxConstants.TOPIC_POWERBANK_CONNECTED, EmqxConstants.TOPIC_POWERBANK_UNLOCK, EmqxConstants.TOPIC_PROPERTY_POST};
            client.subscribe(topics);

            return true;

        } catch (MqttException e) {
            log.info("连接失败");
            e.printStackTrace(); //输出错误信息
        }
        return false;
    }

    /*创建MQTT连接对象配置类*/
    private MqttConnectOptions mqttConnectOptions() {
        //连接mqtt时进行相应设置
        MqttConnectOptions  options = new MqttConnectOptions();
        options.setUserName(emqxProperties.getUsername());
        options.setPassword(emqxProperties.getPassword().toCharArray());

        options.setAutomaticReconnect(true);//是否自动重新连接
        options.setCleanSession(true);//是否清除之前的连接信息

        options.setConnectionTimeout(emqxProperties.getConnectionTimeout());//连接超时时间

        //心跳机制，用于判断mqtt服务与client是否保持连接，每个一段时间会ping，没有通信则认为断开连接
        options.setKeepAliveInterval(emqxProperties.getKeepAliveInterval());

        return options;
    }

    /**
     * 封装发布消息到emqx的方法
     * @param topic
     * @param data
     */
    public void publish(String topic, String data) {

        try {
            MqttMessage message = new MqttMessage(data.getBytes());
            message.setQos(2);
            client.publish(topic,message);

        } catch (MqttException e) {

            log.info("消息发布失败");
            e.printStackTrace();
        }

    }
}
